import smtplib
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.utils import formataddr
from jinja2 import Environment, PackageLoader
from jinja2.exceptions import TemplateNotFound
from functools import wraps
import logging


def check(*args):
    assert all(lambda i:isinstance(i, str) for i in args)
    def method_wrapper(func):
        @wraps(func)
        def method(self, *margs, **kwargs):
            for arg in args:
                try:
                    assert getattr(self, arg)
                except:
                    raise Exception("self.%s should be True"%arg)
            return func(self, *margs, **kwargs)
        return method
    return method_wrapper

class EmailSender:
    def __init__(self, smtp_server, template_dir="./templates", template_file="index.html"):
        self.logger = logging.getLogger(__name__)
        self.smtp_server = smtplib.SMTP_SSL(smtp_server)
        self.env = Environment(loader=PackageLoader('__main__', "templates"))
        self.set_template(template_file)
        self.has_logined = False

    def login(self, username, password):
        if self.smtp_server.login(username, password):
            self.has_logined = True

    def set_template(self, template_file=None):
        try:
            self.template = self.env.get_template(template_file)
        except TemplateNotFound:
            self.template = Environment(loader=PackageLoader('hzutils', "templates")).get_template(template_file)

    def make_email(self, text, images=None):
        images = images or []
        mail = MIMEMultipart()
        html = self.template.render(text=text, images=images)
        text_part = MIMEText(html, "html", _charset='utf-8')
        mail.attach(text_part)
        for i, image in enumerate(images):
            with open(image, "rb") as f:
                img = MIMEImage(f.read())
            img.add_header('Content-ID', '<image%d>'%(i+1))
            mail.attach(img)
        return mail

    @check("has_logined")
    def send_mail(self, mail_from, mail_to, subject, text="", images=None):
        mail = self.make_email(text, images)
        mail["Subject"] = Header(subject, "utf-8")
        mail["From"] = formataddr([mail_from, mail_from])
        mail["To"] = formataddr([mail_to, mail_to])
        try:
            self.smtp_server.sendmail(mail_from, mail_to, mail.as_string())
        except:
            self.logger.error("发送邮件失败")
            return False
        self.logger.info("发送邮件成功")
        return True
